package com.jwsoft.manager.core.integration.impl;

import cn.hutool.core.convert.Convert;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bifang.assistant.common.vo.BaseVO;
import com.bifang.engine.assistant.core.annotation.ApiService;
import com.bifang.engine.assistant.core.annotation.OpApi;
import com.bifang.engine.assistant.core.annotation.SaveOplog;
import com.bifang.engine.assistant.core.enums.AuTypeEnum;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.bifang.engine.assistant.core.enums.FuncTypeEnum;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.engine.assistant.core.utils.SessionUtil;
import com.bifang.engine.cache.jetcache.utils.JetCacheUtils;
import com.bifang.engine.cache.redis.RedisHelper;
import com.bifang.engine.data.core.util.PagerUtil;
import com.bifang.module.base.common.vo.dict.DictAreaVO;
import com.bifang.module.base.common.vo.dict.SelectVO;
import com.bifang.module.base.common.vo.tree.TreeVO;
import com.bifang.module.base.core.helper.DictHelper;
import com.bifang.module.base.core.integration.DictIntegration;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jwsoft.manager.common.constant.EduCache;
import com.jwsoft.manager.common.enums.EduAddressTreeDictEnum;
import com.jwsoft.manager.common.vo.addressParse.Address;
import com.jwsoft.manager.common.vo.eduAddressTreeOriginal.EduAddressTreeOriginalKeyVO;
import com.jwsoft.manager.common.vo.eduAddressTreeOriginal.EduAddressTreeOriginalQueryVO;
import com.jwsoft.manager.common.vo.eduAddressTreeOriginal.EduAddressTreeOriginalVO;
import com.jwsoft.manager.common.vo.eduAddressTreeOriginal.OriginalInfoVO;
import com.jwsoft.manager.core.dao.model.EduAddressTreeOriginal;
import com.jwsoft.manager.core.dao.service.EduAddressTreeOriginalService;
import com.jwsoft.manager.core.integration.EduAddressTreeOriginalIntegration;
import com.jwsoft.manager.core.util.EduHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 地址树参数表业务实现类
 *
 * @author zhiyuan
 * @since 2024-01-08
 */
@ApiService(funcCode = "addressTreeOriginal", title = "地址树参数表")
public class EduAddressTreeOriginalIntegrationImpl implements EduAddressTreeOriginalIntegration {

    @Autowired
    public EduAddressTreeOriginalService eduAddressTreeOriginalService;
    @Autowired
    public DictIntegration dictIntegration;
    private static final String SUPER_ADMIN_NAME = "SUPERADMIN";
    @Autowired
    private DictHelper dictHelper;
    @Autowired
    private EduHelper eduHelper;

    @Autowired
    private RedisHelper redisHelper;
    @Override
    @OpApi(funcCode = "addressTreeOriginal0001", title = "地址树参数表分页查询", funcType = FuncTypeEnum.query)
    public PageInfo<EduAddressTreeOriginalVO> getList(EduAddressTreeOriginalQueryVO vo) {
        // 开启分页
        if (vo.getPageNum() == null || vo.getPageSize() == null) {
            //如果不传入分页参数，默认最大取1000条
            vo.setPageNum(1);
            vo.setPageSize(1000);
        }
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
        List<EduAddressTreeOriginal> list = eduAddressTreeOriginalService.list();
        if (CollectionUtils.isEmpty(list)) {
            // 判断是否为空，为空则返回空参数
            return PagerUtil.createEmptyPagerInfo(vo.getPageNum(), vo.getPageSize());
        }
        // 不为空则获取分页结果
        PageInfo<EduAddressTreeOriginal> pageInfo = new PageInfo<>(list);
        // 返回参数需要通过common层的vo实体类，用该方法可以批量转换
        List<EduAddressTreeOriginalVO> resultList = Convert.toList(EduAddressTreeOriginalVO.class, pageInfo.getList());
        // 转义数据字典值
        // dictHelper.valueToName(resultList, Arrays.asList(DemoDictEnum.values()));
        return PagerUtil.parsePagerVo(resultList, pageInfo);
    }

    @Override
    @OpApi(funcCode = "addressTreeOriginal0002", title = "地址树参数表根据主键查询详情", funcType = FuncTypeEnum.query)
    public EduAddressTreeOriginalVO getById(EduAddressTreeOriginalKeyVO vo) {
        EduAddressTreeOriginal entity = eduAddressTreeOriginalService.getById(vo.getAddressId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("查询不到详细信息!");
        }
        EduAddressTreeOriginalVO result = Convert.convert(EduAddressTreeOriginalVO.class, entity);
        return result;
    }
    /** 保存前统一校验*/
    @Override
    @OpApi(funcCode = "addressTreeOriginal0003", title = "地址树参数表保存前校验", funcType = FuncTypeEnum.other ,checkPrivilege = BoolEnum.FALSE)
    public void checkSave(EduAddressTreeOriginalVO vo) {
        //主键为空为新增校验

        //主键不为空为修改校验
    }

    @Override
    @OpApi(funcCode = "addressTreeOriginal0004", title = "地址树参数表新增", funcType = FuncTypeEnum.insert)
    @Transactional
    public EduAddressTreeOriginalVO add(EduAddressTreeOriginalVO vo) {
        //保存前校验
        checkSave(vo);
        //保存数据
        EduAddressTreeOriginal entity = Convert.convert(EduAddressTreeOriginal.class, vo);
        eduAddressTreeOriginalService.save(entity);
        //将主键设置回vo使操作日志可以取到
        vo.setAddressId(entity.getAddressId());
        clearTreeCache();
        return vo;
    }

    @Override
    @OpApi(funcCode = "addressTreeOriginal0005", title = "地址树参数表修改", funcType = FuncTypeEnum.update)
    @Transactional
    public EduAddressTreeOriginalVO edit(EduAddressTreeOriginalVO vo) {
        if (ObjectUtils.isEmpty(vo.getAddressId())) {
            throw new AppException("传入需要修改的主键不能为空!");
        }
        EduAddressTreeOriginal oldEntity = eduAddressTreeOriginalService.getById(vo.getAddressId());
        if (ObjectUtils.isEmpty(oldEntity)) {
            throw new AppException("查询不到需要修改的信息!");
        }
        //保存前校验
        checkSave(vo);
        //保存数据
        EduAddressTreeOriginal entity = Convert.convert(EduAddressTreeOriginal.class, vo);
        eduAddressTreeOriginalService.updateById(entity);
        clearTreeCache();
        return vo;
    }

    @Override
    @OpApi(funcCode = "addressTreeOriginal0006", title = "地址树参数表根据主键删除", funcType = FuncTypeEnum.delete)
    @Transactional
    public void del(EduAddressTreeOriginalKeyVO vo) {
        if (ObjectUtils.isEmpty(vo.getAddressId())) {
            throw new AppException("传入需要删除的数据主键不能为空!");
        }
        EduAddressTreeOriginal entity = eduAddressTreeOriginalService.getById(vo.getAddressId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("未找到需要删除的信息!");
        }
        //校验要删除的节点是否有子节点信息
        long count = eduAddressTreeOriginalService.count(Wrappers.<EduAddressTreeOriginal>lambdaQuery()
                .eq(EduAddressTreeOriginal::getParentId, entity.getAddressId()));
        if (count > 0) {
            throw new AppException("该节点下有子节点,不能删除！");
        }
        boolean removeFlag = eduAddressTreeOriginalService.removeById(vo.getAddressId());
        if (removeFlag){
            clearTreeCache();
        }
    }

    @OpApi(funcCode = "addressTreeOriginal0008", title = "分页获取下级节点", funcType = FuncTypeEnum.query)
    @Override
    public PageInfo<EduAddressTreeOriginalVO> getListByParentId(EduAddressTreeOriginalQueryVO vo) {
        // 开启分页
        if (vo.getPageNum() == null || vo.getPageSize() == null) {
            //如果不传入分页参数，默认最大取1000条
            vo.setPageNum(1);
            vo.setPageSize(1000);
        }
        //得到系统配置的统筹区
        String areaCode = eduHelper.thisAreaCode();
        QueryWrapper<EduAddressTreeOriginal> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .ne(EduAddressTreeOriginal::getAreaType,"error");
        if (vo.getParentId() == null || vo.getParentId() == 0L){
            if (StringUtils.isBlank(areaCode)){
                Set<String> systemPrivileges = SessionUtil.getSystemPrivileges();
                if (!systemPrivileges.contains(SUPER_ADMIN_NAME)) {
                    throw new AppException("你的账号或组织没有配置行政区划，请联系管理配置");
                }
                //获取行政区划所属地址节点id
                EduAddressTreeOriginal original = eduAddressTreeOriginalService.getOne(Wrappers.<EduAddressTreeOriginal>lambdaQuery()
                        .eq(EduAddressTreeOriginal::getAreaCode, areaCode),false);
                if (original != null){
                    vo.setParentId(original.getParentId());
                }else{
                    vo.setParentId(0L);
                }
            }else{
                queryWrapper.lambda().eq(EduAddressTreeOriginal::getAreaCode, areaCode);
                vo.setParentId(null);
            }
        }
        queryWrapper.lambda().eq(vo.getParentId() != null ,EduAddressTreeOriginal::getParentId,
                vo.getParentId())
                .orderByAsc(EduAddressTreeOriginal::getOrderNo,EduAddressTreeOriginal::getAreaCode,EduAddressTreeOriginal::getAreaName);
        PageHelper.startPage(vo.getPageNum(), vo.getPageSize());
        List<EduAddressTreeOriginal> list = eduAddressTreeOriginalService.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return PageInfo.emptyPageInfo();
        }
        PageInfo<EduAddressTreeOriginal> pageInfo = new PageInfo<>(list);
        List<EduAddressTreeOriginalVO> resultList = Convert.toList(EduAddressTreeOriginalVO.class, list);
        dictHelper.valueToName(resultList, Arrays.asList(EduAddressTreeDictEnum.values()));
        return PagerUtil.parsePagerVo(resultList, pageInfo);

    }

    @OpApi(
            funcCode = "addressTreeOriginal0009",
            title = "保存地址树节点详细信息",
            funcType = FuncTypeEnum.update,
            publicFlag = BoolEnum.TRUE)
    @Override
    @Transactional(rollbackFor = Exception.class)
    public EduAddressTreeOriginalVO saveAddressTreeInfo(OriginalInfoVO vo) {
        if (ObjectUtils.isEmpty(vo)) {
            throw new AppException("保存的信息不能为空!");
        }
        if (ObjectUtils.isEmpty(vo.getData().getAreaName())) {
            throw new AppException("树节点名称！");
        }
        if (ObjectUtils.isEmpty(vo.getData().getAreaType())) {
            throw new AppException("地址类型不能为空！");
        }
        if (ObjectUtils.isEmpty(vo.getData().getParentId())) {
            throw new AppException("地址父节点信息不能为空！");
        }
        EduAddressTreeOriginalVO originalVO = vo.getData();
        //判断父id下是否有同名地址数据
        QueryWrapper<EduAddressTreeOriginal> queryWrapper = new QueryWrapper<>();
        if (originalVO.getAddressId() == null){
            queryWrapper.lambda()
                    .eq(EduAddressTreeOriginal::getParentId,originalVO.getParentId())
                    .eq(EduAddressTreeOriginal::getAreaName, originalVO.getAreaName());
            if (eduAddressTreeOriginalService.count(queryWrapper) != 0){
                throw new AppException("该节点下已存在同名节点:"+originalVO.getAreaName());
            }
        }
        if (!ObjectUtils.isEmpty(vo.getSearchTermList())) {
            List<String> searchTermList = vo.getSearchTermList();
            String searchTerm = StringUtils.join(searchTermList, "#");
            originalVO.setSearchTerm(searchTerm);
        } else {
            originalVO.setSearchTerm(originalVO.getAreaName());
        }
        if(originalVO.getMajorPointer() == null){
            originalVO.setMajorPointer(0L);
        }
        EduAddressTreeOriginal originalNode = Convert.convert(EduAddressTreeOriginal.class, originalVO);
        boolean saveFlag = eduAddressTreeOriginalService.saveOrUpdate(originalNode);
        if (saveFlag) {
            clearTreeCache();
        }
        return originalVO;
    }

    @OpApi(funcCode = "addressTreeOriginal0010", title = "参数表级联查询", funcType = FuncTypeEnum.query,publicFlag = BoolEnum.TRUE)
    @Override
    public List<TreeVO> getCascadeOption(EduAddressTreeOriginalQueryVO vo) {
        //得到系统配置的统筹区
        String areaCode = eduHelper.thisAreaCode();
        Cache<String, List<TreeVO>> treeCache = JetCacheUtils.create(EduCache.EDU_ADDRESS_TREE_ORIGINAL, CacheType.BOTH, Duration.ofDays(30),Duration.ofSeconds(300));
        if (treeCache != null){
            List<TreeVO> list=treeCache.get(areaCode);
            if (!CollectionUtils.isEmpty(list)){
                return list;
            }
        }
        List<String> areaCodeList = new ArrayList<>();
        //根据系统配置的统筹区划，得到所属行政区划
        List<SelectVO> selectVOList = dictIntegration.getDistrictByOrg(new DictAreaVO());
        areaCodeList = selectVOList.stream()
                .map(SelectVO::getDictKey)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(areaCodeList)){
            areaCodeList.add(vo.getAreaCode());
        }
        List<TreeVO> treeVOList = new ArrayList<>();
        //获取行政区划所属地址节点id
        List<EduAddressTreeOriginal> originalList = eduAddressTreeOriginalService.list(Wrappers.<EduAddressTreeOriginal>lambdaQuery()
                .select(EduAddressTreeOriginal::getAddressId,EduAddressTreeOriginal::getAreaName)
                .in(EduAddressTreeOriginal::getAreaCode, areaCodeList));
        if (!CollectionUtils.isEmpty(originalList)){
            for (EduAddressTreeOriginal original : originalList) {
                //得到父节点下的所有子节点数据
                List<EduAddressTreeOriginal> allDescendants = eduAddressTreeOriginalService.getAllDescendants(original.getAddressId());
                allDescendants.add(original);
                for (EduAddressTreeOriginal treeOriginal : allDescendants) {
                    TreeVO treeVO = new TreeVO();
                    treeVO.setKey(String.valueOf(treeOriginal.getAddressId()));
                    // 选择后获取的值
                    treeVO.setValue(treeOriginal.getAreaName());
                    treeVO.setTitle(treeOriginal.getAreaName());
                    treeVO.setParentKey(String.valueOf(treeOriginal.getParentId()));
                    treeVOList.add(treeVO);
                }
            }
            treeVOList = eduAddressTreeOriginalService.builderTreeList(treeVOList);
            treeCache.put(areaCode,treeVOList);
        }
        return treeVOList;
    }

    @OpApi(funcCode = "addressTreeOriginal0011", title = "根据所属行政区划获取街道信息", funcType = FuncTypeEnum.query,publicFlag = BoolEnum.TRUE)
    @Override
    public List<SelectVO> getStreetByAreaCode(EduAddressTreeOriginalQueryVO vo) {
        if (StringUtils.isBlank(vo.getAreaCode())){
            throw new AppException("所属行政区划不能为空");
        }
        QueryWrapper<EduAddressTreeOriginal> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(EduAddressTreeOriginal::getAreaCode,vo.getAreaCode());
        EduAddressTreeOriginal original = eduAddressTreeOriginalService.getOne(queryWrapper, false);
        if (original == null){
            return new ArrayList<>();
        }
        queryWrapper.clear();
        queryWrapper.lambda()
                .eq(EduAddressTreeOriginal::getParentId,original.getAddressId())
                .isNotNull(EduAddressTreeOriginal::getAreaCode);
        List<EduAddressTreeOriginal> list = eduAddressTreeOriginalService.list(queryWrapper);
        if (CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }
        List<SelectVO> collect = list.stream().map(item -> {
            SelectVO selectVO = new SelectVO();
            selectVO.setDictKey(item.getAreaCode());
            selectVO.setDictValue(item.getAreaName());
            selectVO.setAreaCode(item.getAreaCode());
            return selectVO;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    @OpApi(funcCode = "addressTreeOriginal0012", title = "清除参数表缓存", funcType = FuncTypeEnum.delete,publicFlag = BoolEnum.TRUE)
    public void clearTreeCache(BaseVO vo) {
        this.clearTreeCache();
    }

    private void clearTreeCache(){
        //1，清除参数树缓存数据
        Cache<String, List<TreeVO>> treeCache = JetCacheUtils.create(EduCache.EDU_ADDRESS_TREE_ORIGINAL, CacheType.BOTH, Duration.ofDays(30),Duration.ofSeconds(300));
        if (treeCache!=null){
            String areaCode = eduHelper.thisAreaCode();
            treeCache.remove(areaCode);
        }

        //2，清除参数表缓存数据
        Cache<String,List<Address>> addressCache = JetCacheUtils.create(EduCache.EDU_ADDRESS_TREE_ALL, CacheType.BOTH, Duration.ofDays(30),Duration.ofSeconds(300));
        if (addressCache!=null){
            addressCache.remove("all");
        }

        //3. 清除地址树获取当前统筹区信息缓存
        redisHelper.del(EduCache.EDU_ADDRESS_TREE_MATCH_AREA);
    }


}
